//
// $Id: SampleManager.java,v 1.21 2004/08/27 18:51:26 mdb Exp $

package com.chuhay.elemwar;

import static com.chuhay.elemwar.ElemWarConstants.*;

import java.awt.Point;
import java.util.Random;

import com.chuhay.elemwar.ElemWarObject.Hex;
import com.chuhay.elemwar.ElemWarObject.Piece;
import com.threerings.crowd.data.BodyObject;
import com.threerings.crowd.data.PlaceObject;

import com.threerings.parlor.Log;
import com.threerings.parlor.game.server.GameManager;
import com.threerings.parlor.turn.server.TurnGameManager;
import com.threerings.parlor.turn.server.TurnGameManagerDelegate;

import com.threerings.toybox.data.ToyBoxGameConfig;

/**
 * Handles the server side of the game.
 */
public class ElemWarManager extends GameManager implements TurnGameManager {

   /** Our game object. */
   protected ElemWarObject _gameobj;

   /** Our game configuration. */
   protected ToyBoxGameConfig _gameconf;

   /** Delegate for turn-related stuff */
   protected TurnGameManagerDelegate _turndel;

   /** A reference to an instance of the logic class */
   protected ElemWarLogic _logic;

   public ElemWarManager () {
      addDelegate(_turndel = new TurnGameManagerDelegate(this) {
         protected void setNextTurnHolder () {
            _turnIdx = (_turnIdx + 1) % 2;
         }

         protected void setFirstTurnHolder () {
            _turnIdx = 0;
         }
      });
   }

   @Override
   // from PlaceManager
   public void didInit () {
      super.didInit();

      // get a casted reference to our game configuration
      _gameconf = (ToyBoxGameConfig) _config;
   }

   @Override
   // from PlaceManager
   public void didStartup () {
      super.didStartup();

      // grab our own casted game object reference
      _gameobj = (ElemWarObject) super._gameobj;

      _logic = new ElemWarLogic(_gameobj);
   }

   @Override
   // from PlaceManager
   public void didShutdown () {
      super.didShutdown();
   }

   @Override
   // from PlaceManager
   protected PlaceObject createPlaceObject () {
      return new ElemWarObject();
   }

   @Override
   // from GameManager
   protected void gameWillStart () {
      super.gameWillStart();

      int x, y, i;
      int n = 0;
      
      // Create RNG for creation of filled hexes
      Random rnd = new Random(System.currentTimeMillis());

      // Create hex grid
      // Neutral board
      for (y = 0; y < boardRowEnds.length; y++)
         for (x = boardRowEnds[y][0]; x < boardRowEnds[y][1]; x++) {
            Point p = ElemWarBoardView.translateCoords(x, y);
            ElemWarObject.Hex hex = new ElemWarObject.Hex();
            hex.hexID = y * ElemWarBoardView._size.width + x;
            hex.gridX = x;
            hex.gridY = y;
            hex.x = p.x;
            hex.y = p.y;
            hex.hexType = rnd.nextDouble() < 0.90 ? HEX_EMPTY : HEX_FILLED;
            hex.hexArea = AREA_BOARD;
            hex.selected = SELECT_UNSELECTED;
            hex.pieceID = -1;
            _gameobj.addTo_hexes(hex);
         }

      // Goal areas
      for (i = 0; i < 2; i++)
         for (y = 0; y < goalRowEnds[i].length; y++)
            for (x = goalRowEnds[i][y][0]; x < goalRowEnds[i][y][1]; x++) {
               Point p = ElemWarBoardView.translateCoords(x, y);
               ElemWarObject.Hex hex = new ElemWarObject.Hex();
               hex.hexID = y * ElemWarBoardView._size.width + x;
               hex.gridX = x;
               hex.gridY = y;
               hex.x = p.x;
               hex.y = p.y;
               hex.hexType = HEX_EMPTY;
               hex.hexArea = i == 0 ? AREA_ICE_GOAL : AREA_FIRE_GOAL;
               hex.selected = SELECT_UNSELECTED;
               hex.pieceID = -1;
               _gameobj.addTo_hexes(hex);
            }

      // Home areas
      for (i = 0; i < 2; i++)
         for (y = 0; y < homeRowEnds[i].length; y++)
            for (x = homeRowEnds[i][y][0]; x < homeRowEnds[i][y][1]; x++) {
               Point p = ElemWarBoardView.translateCoords(x, y + 6);
               ElemWarObject.Hex hex = new ElemWarObject.Hex();
               hex.hexID = (y + 6) * ElemWarBoardView._size.width + x;
               hex.gridX = x;
               hex.gridY = y + 6;
               hex.x = p.x;
               hex.y = p.y;
               hex.hexType = i == 1 ? HEX_ICE : HEX_FIRE;
               hex.selected = SELECT_UNSELECTED;
               hex.hexArea = i == 1 ? AREA_ICE_HOME : AREA_FIRE_HOME;

               // Also create a piece for this home area hex
               p = ElemWarBoardView.translateCoords(x, y + 6);
               ElemWarObject.Piece piece = new ElemWarObject.Piece();
               piece.pieceID = n++;
               piece.gridX = x;
               piece.gridY = y + 6;
               piece.x = p.x;
               piece.y = p.y;
               piece.pieceType = i == 0 ? PIECE_FIRE : PIECE_ICE;

               // Add the piece to the hex and add the hex to the board
               hex.pieceID = piece.pieceID;
               _gameobj.addTo_pieces(piece);
               _gameobj.addTo_hexes(hex);
            }
   }

   @Override
   // from GameManager
   protected void gameDidEnd () {
      super.gameDidEnd();
   }

   // Invoked by client controllers to move pieces around the board
   public void movePiece (BodyObject player, int selectedHexID, int clickedHexID) throws IllegalAccessException {
      if (_playerOids[_turndel.getTurnHolderIndex()] != player.getOid()) {
         Log.warning("Requested to place piece by non-turn holder " + "[who=" + player.who() + ", turnHolder=" + _gameobj.turnHolder + "].");
         throw new IllegalAccessException("Requested to place piece by non-turn holder " + "[who=" + player.who() + ", turnHolder=" + _gameobj.turnHolder + "].");
      }

      // Get hexes and piece from ID's
      Hex srcHex = _gameobj._hexes.get(selectedHexID);
      Hex destHex = _gameobj._hexes.get(clickedHexID);
      Piece piece = _gameobj._pieces.get(srcHex.pieceID);

      // If move is valid, move piece
      if (_logic.getMoveValidity(destHex, srcHex, piece.pieceType, true) == VALID_VALID_MOVE) {
         // Move the piece to the new location
         piece.gridX = destHex.gridX;
         piece.gridY = destHex.gridY;
         piece.x = destHex.x;
         piece.y = destHex.y;

         // Associate the piece with the destination hex
         destHex.pieceID = piece.pieceID;
         srcHex.pieceID = -1;

         // Update the destination hex type
         switch (piece.pieceType) {
         case PIECE_FIRE:
            destHex.hexType = HEX_FIRE;
            break;
         case PIECE_ICE:
            destHex.hexType = HEX_ICE;
            break;
         }

         // Update the game object with the new hexes and piece
         _gameobj.update_hexes(srcHex);
         _gameobj.update_hexes(destHex);
         _gameobj.update_pieces(piece);

         // End the turn
         _turndel.endTurn();
      } else {
         Log.warning("Received illegal move request " + "[who=" + player.who() + ", piece=" + piece + "].");
         throw new IllegalAccessException("Received illegal move request " + "[who=" + player.who() + ", piece=" + piece + "].");
      }
   }

   public void turnDidEnd () {
      int [] numFilledGoal = new int [2];
      for (Hex hex : _gameobj._hexes) {
         // If hex is a goal area...
         if (hex.hexArea == AREA_FIRE_GOAL || hex.hexArea == AREA_ICE_GOAL)
            // Count it for the proper player if it's not empty
            if (hex.pieceID != -1)
               numFilledGoal[_gameobj._pieces.get(hex.pieceID).pieceType]++;
      }

      // If one of the goals is full, end the game
      for (int n : numFilledGoal)
         if (n == 12)
            endGame();
   }

   public void turnDidStart () {}

   public void turnWillStart () {}

   @Override
   protected void assignWinners (boolean [] winners) {
      super.assignWinners(winners);
      int [] counts = new int [2];
      for (Hex hex : _gameobj._hexes) {
         switch (hex.hexArea) {
         case AREA_BOARD:
            // If hex is board, count 1 point for a hex of the player's type
            if(hex.hexType == HEX_FIRE || hex.hexType == HEX_ICE)
               counts[hex.hexType]++;
            break;
         case AREA_FIRE_GOAL:
            // If hex is goal and not empty, count 3 points for that player
            if(hex.pieceID != -1)
               counts[ElemWarConstants.PIECE_FIRE]+=3;
            break;
         case AREA_ICE_GOAL:
            // If hex is goal and not empty, count 3 points for that player
            if(hex.pieceID != -1)
               counts[ElemWarConstants.PIECE_ICE]+=3;
            break;
         default:
            break;
         }
      }

      // now set a boolean indicating which player is the winner (note that
      // if it is a tie, we want to set both values to true)
      winners[0] = (counts[0] >= counts[1]);
      winners[1] = (counts[1] >= counts[0]);
      
      // Display final score in chat box
      this.systemMessage(null, _gameobj.players[0] + ": "+counts[0]);
      this.systemMessage(null, _gameobj.players[1] + ": "+counts[1]);
   }
}
